home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / bookmark_previews-0.6.5-fx.xpi / chrome / content / albumview.js next >
Text File  |  2008-05-27  |  17KB  |  472 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is the Bookmark Previews extension.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * John Marshall <JohnM555@gmail.com>.
  18.  * Portions created by the Initial Developer are Copyright (C) 2007
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   John Marshall <JohnM555@gmail.com>
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. var AlbumView = {
  39.   initiated : false,
  40.   container : null,
  41.   img_container : null,
  42.   caption : null,
  43.   keepFocus : true,
  44.   updatedSelection : false,
  45.   current: 0, target: 0, timer: 0,
  46.   middle : 0, vscale : 0, hscale : 0, max : 0,
  47.   MAX_NODES: 9,
  48.   lastOffsets : [],
  49.   itemNodes : [],
  50.   itemImages : [],
  51.   itemProps : [],
  52.   canRefresh : true,
  53.   STEP_INTERVAL : 50,
  54.   SHOW_REFLECTION : false,
  55.   init : function(aContainer, aImgContainer, aCaption){
  56.     this.canvas = document.getElementById("albumcanvas");
  57.     this.container = document.getElementById("albumview-container");
  58.     this.img_container = document.getElementById("albumview-image-container");
  59.     this.caption = document.getElementById("albumview-caption");
  60.     this.scrollbar = document.getElementById("albumview-scrollbar");
  61.     this.container.addEventListener('click',this.displayClick,false);
  62.     this.container.addEventListener('dblclick',this.displayDblClick,false);
  63.     this.container.addEventListener('DOMMouseScroll', this.wheel, false);
  64.     this.scrollbar.addEventListener('DOMAttrModified',this.onScroll,false);
  65.     this.container.addEventListener('DOMAttrModified',this.onCollapse,false);
  66.     this.container.addEventListener('keypress',this.handleKeypress,true);
  67.     //this.container.addEventListener('click',this.containerClick,false);
  68.  
  69.   },
  70.   uninit : function(){
  71.     this.scrollbar.removeEventListener('DOMAttrModified',this.onScroll,false);
  72.     this.container.removeEventListener('click',this.displayClick,false);
  73.     this.container.removeEventListener('dblclick',this.displayDblClick,false);
  74.     this.container.removeEventListener('DOMMouseScroll', this.wheel, false);
  75.     this.container.removeEventListener('DOMAttrModified',this.onCollapse,false);
  76.     this.container.removeEventListener('keypress',this.handleKeypress,true);
  77.     //this.container.removeEventListener('click',this.containerClick,false);
  78.     this.initiated = false;
  79.   },
  80.   /* called on start and on refresh
  81.     caches unchanging values
  82.     orient = -1, its initializing the album view
  83.     orient = 0, resized horizontally
  84.     orient = 1, resized vertically
  85.   */
  86.   refresh : function(orient) {
  87.     this.canRefresh = false;
  88.     this.width = this.container.boxObject.width;
  89.     this.middle = this.width / 2;
  90.     if (!this.previousHeight)
  91.       this.height = Math.ceil(.25 * this.width);
  92.     else{
  93.       this.height = this.previousHeight;
  94.       this.previousHeight = null;
  95.     }
  96.     var otherHeight = this.caption.parentNode.boxObject.height;
  97.     var curHeight = this.container.boxObject.height - otherHeight;
  98.     var availableHeight = this.container.parentNode.boxObject.height - otherHeight;
  99.     if (this.initiated && orient!=0){
  100.       availableHeight = this.container.boxObject.height - otherHeight;
  101.     } else if (!this.initiated)
  102.       this.initiated = true;
  103.     if (availableHeight<this.height){
  104.       this.height = availableHeight;
  105.     }
  106.     this.slope = (this.height)/(this.width/2);
  107.     this.vscale = this.height * 1.193181818;
  108.     this.hscale = 5 * this.height / 2;
  109.     this.scrollbar.width = this.width-10;
  110.     this.setSize(this.img_container, this.width, this.height);
  111.     this.setSize(this.img_container.parentNode, this.width, this.height);
  112.     this.img_container.parentNode.parentNode.width = this.width;//.style.maxWidth = width;
  113.     this.container.height = this.height+otherHeight;
  114.     /* Display images in current order */
  115.     this.moveTo(this.current);
  116.     this.canRefresh = true;
  117.   },
  118.   onCollapse : function(event){
  119.     if (event.attrName == "collapsed"){
  120.       var collapsed = event.newValue;
  121.       if (collapsed && AlbumView.height >=20){
  122.         AlbumView.previousHeight = AlbumView.height;
  123.       } else
  124.         AlbumView.previousHeight = 0;
  125.     }
  126.   },
  127.   step : function() {
  128.     var self = AlbumView;
  129.     if (self.target < self.current-1 || self.target > self.current+1)    {
  130.         self.moveTo(self.current + (self.target-self.current)/3);
  131.         setTimeout(self.step, self.STEP_INTERVAL);
  132.         self.timer = 1;
  133.     } else {
  134.       self.timer = 0;
  135.       self.current = self.target;
  136.       var targetIndex = -AlbumView.target/150
  137.       if (AlbumViewUtils && AlbumViewUtils.selectIndex)
  138.         AlbumViewUtils.selectIndex(self.itemNodes[targetIndex]);
  139.     }
  140.   },
  141.   glideToIndex : function(index){
  142.     var target = index * -150;
  143.     AlbumView.glideTo(target);
  144.   },
  145.   glideTo : function(aTarget,updateSelection) {
  146.     /* Animate gliding to new x position */
  147.     this.target = aTarget;
  148.     var targetIndex = -this.target/150;
  149.     var currentIndex = -this.current/150;
  150.     if (targetIndex>=this.max){
  151.       if (currentIndex<this.max-1){
  152.         this.target = -(this.max-1)*150;
  153.         targetIndex = -this.target/150;
  154.       }
  155.     }
  156.     if (this.timer == 0 && targetIndex<this.max && targetIndex!=currentIndex){
  157.       setTimeout(this.step, 50);
  158.       this.timer = 1;
  159.     }
  160.     this.updateCaption(Math.ceil(targetIndex));
  161.   },
  162.   updateCaption : function(index){
  163.     if (index<this.max && index>-1 && this.itemProps.length>0){
  164.       /* Display new caption */
  165.       var caption = this.itemProps[index].caption;
  166.       this.caption.value = caption;
  167.       /* Update scrollbar */
  168.       this.scrollbar.setAttribute("curpos",index);
  169.     } else{
  170.       this.caption.value = "";
  171.       this.scrollbar.setAttribute("curpos",0);
  172.     }
  173.   },
  174.   onScroll : function(event){
  175.     if (event.attrName == "curpos"){
  176.       AlbumView.glideToIndex(event.newValue);
  177.     }
  178.   },
  179.   /* main part of the transition */
  180.   moveTo : function(x) {
  181.     //dump("moveto: "+x+"\n");
  182.     try{
  183.     var self = AlbumView;
  184.     self.current = x;
  185.     var targetIndex = Math.ceil(-self.target / 150);
  186.     var currentIndex = Math.ceil(-self.current / 150);
  187.  
  188.     var start=targetIndex-self.MAX_NODES;
  189.     if (start<0)
  190.       start=0;
  191.     var end=targetIndex+self.MAX_NODES;
  192.     if (end>self.max - 1)
  193.       end = self.max - 1;
  194.  
  195.     var ctx = self.img_container.getContext("2d");
  196.     ctx.clearRect(0,0,self.width,self.height);
  197.  
  198.     function moveLoop(index,increasing){
  199.       self.computeProperties(x,self.itemProps[index]);
  200.       var success = self.drawImage(index, targetIndex);
  201.       x = increasing?x+150:x-150;
  202.     }
  203.  
  204.     x = x + 150 * start;
  205.     for (var index = start; index < targetIndex; index++){
  206.       moveLoop(index,true);
  207.     }
  208.     x = self.current + end * 150;
  209.     for (var index = end; index>=targetIndex; index--){
  210.       moveLoop(index, false);
  211.     }
  212.     }catch(e){Components.utils.reportError("MOVETO: "+e);}
  213.   },
  214.   computeProperties : function(x, props){
  215.     var z = Math.sqrt(10000 + Math.pow(x,2))+100;
  216.     if (!props) return;
  217.     props.width = Math.floor(200 / z * this.vscale);
  218.     props.height = Math.floor(220 / z * this.vscale -
  219.                    25 / z * this.hscale);
  220.     props.left = Math.floor((x / (Math.sqrt(10000 + Math.pow(x,2))+300))*this.hscale + this.middle - props.width/2);
  221.     props.top = Math.floor((this.height - props.height)/2);
  222.     //dump("props["+x+"] = width: "+props.width+" height: "+props.height+" left: "+props.left+" top: "+props.top+"\n");
  223.   },
  224.   /* returns true if it should be drawn, false if it shouldn't(out of bounds)*/
  225.   drawImage : function(index, targetIndex){
  226.     try{
  227.     var self = AlbumView;
  228.     if (!targetIndex)
  229.       targetIndex = -self.target / 150;
  230.     var offset = index - targetIndex;
  231.     var props = self.itemProps[index];
  232.     if (!props || props.left == null)
  233.       return false;
  234.  
  235.     if (props.left<0 || props.width <= 0 || props.left+props.width>self.width){
  236.       return false;
  237.     }
  238.     var ctx = self.img_container.getContext("2d");
  239.     var img = self.itemImages[index];
  240.     if (img.complete){
  241.       var hoffset = 0, toffset = 0;
  242.       /* not finished... */
  243.       if (false && ctx.transform && offset!=0){/* FF3 only*/
  244.  
  245.         if (!self._tempCanvas){
  246.           self._tempCanvas = document.createElementNS("http://www.w3.org/1999/xhtml","canvas");
  247.         }
  248.         var angle = 0, tanA = 0;
  249.         if (offset < 0){
  250.           angle = -Math.PI / 18;
  251.           tanA = Math.tan(angle);
  252.           hoffset = Math.abs(props.height * tanA * 2);
  253.           toffset = hoffset;
  254.         }
  255.         else{
  256.           angle = Math.PI / 18;
  257.           tanA = Math.tan(angle);
  258.           hoffset = props.height * tanA * 2;
  259.         }
  260.         self.setSize(self._tempCanvas,props.width,props.height+hoffset);
  261.         var ctx2 = self._tempCanvas.getContext("2d");
  262.         ctx2.clearRect(0,0,img.width,props.height+hoffset);
  263.         ctx2.transform(1, tanA, 0, 1, 0, 0);
  264.         ctx2.drawImage(img,0,toffset,props.width,props.height);
  265.         img = self._tempCanvas;
  266.       }
  267.       var adjustedHeight=props.width/img.width*img.height;
  268.       if (props.width>img.width) adjustedHeight = props.height;
  269.       var adjustedTop = (props.height-adjustedHeight)/1+props.top;
  270.       adjustedTop = props.top; adjustedHeight = props.height;
  271.       ctx.drawImage(img,
  272.                     props.left,
  273.                     adjustedTop,
  274.                     props.width,
  275.                     adjustedHeight);
  276.       if (self.SHOW_REFLECTION && ctx.transform){
  277.         var rheight = Math.ceil(props.height/3);
  278.         if (rheight+props.top+props.height>self.height){
  279.           rheight = self.height-props.height-props.top;
  280.         }
  281.         if (rheight>1){
  282.           if (!self._tempCanvas){
  283.             self._tempCanvas = document.createElementNS("http://www.w3.org/1999/xhtml","canvas");
  284.           }
  285.           self.setSize(self._tempCanvas,props.width,props.height+hoffset);
  286.           var ctx2 = self._tempCanvas.getContext("2d");
  287.           ctx2.clearRect(0,0,img.width,props.height+hoffset);
  288.           ctx2.transform(1, 0, 0, -1, 0, props.height);
  289.           ctx2.drawImage(img,0,0,props.width,props.height);
  290.  
  291.           img = self._tempCanvas;
  292.  
  293.           ctx.drawImage(img, 0, 0, img.width, img.height,
  294.                         props.left,
  295.                         props.top+props.height,
  296.                         props.width,
  297.                         rheight);
  298.  
  299.           var lineargradient = ctx.createLinearGradient(0,props.top+props.height,0,props.top+props.height+rheight);
  300.  
  301.           lineargradient.addColorStop(0,'rgba(0,0,0,.3)');
  302.           lineargradient.addColorStop(.5,'rgba(30,30,30,.7)');
  303.           lineargradient.addColorStop(1,'rgba(0,0,0,1)');
  304.           ctx.fillStyle = lineargradient;
  305.           ctx.fillRect(props.left,props.top+props.height,props.width,rheight);
  306.         }
  307.  
  308.       }
  309.  
  310.     }
  311.     //else{
  312.     //  //dump("draw image was called but the image was not complete: "+index+"\n");
  313.     //}
  314.     self.lastOffsets[index] = offset;
  315.     //dump("finish draw image\n");
  316.     }catch(e){Components.utils.reportError(e);}
  317.     return true;
  318.   },
  319.   _getClickTarget : function(event){
  320.     var x = (event.clientX - this.container.boxObject.x);//event.layerX;
  321.     var y = (event.clientY - this.container.boxObject.y);//event.layerY;
  322.     var targetIndex = -this.target / 150;
  323.     /* less than or equal to targetIndex */
  324.     if (x<this.middle){
  325.       for (var i = Math.ceil(targetIndex); i>=0; i--){
  326.         var props = this.itemProps[i];
  327.         if (props && x>=props.left && x<=props.left + props.width){
  328.           return i;
  329.         }
  330.       }
  331.     }
  332.     else{
  333.       for (var i = Math.floor(targetIndex); i< this.max; i++){
  334.         var props = this.itemProps[i];
  335.         if (x>=props.left && x<=props.left + props.width){
  336.           return i;
  337.         }
  338.       }
  339.     }
  340.     return -1;
  341.   },
  342.   displayClick : function(event){
  343.     var index = AlbumView._getClickTarget(event);
  344.     if (index == -1) return;
  345.     if (event.button == 1)
  346.       AlbumViewUtils.performAction(AlbumView.itemNodes[index],event);
  347.     else
  348.       AlbumView.glideTo(index * -150,true);
  349.   },
  350.   displayDblClick : function(event){
  351.     var index = AlbumView._getClickTarget(event);
  352.     if (index != -1){
  353.       AlbumViewUtils.performAction(AlbumView.itemNodes[index],event);
  354.     }
  355.   },
  356.   /* JavaScript mouse wheel */
  357.   handle : function(delta) {
  358.     if  (delta > 0) {
  359.       if(AlbumView.target != 0)
  360.         AlbumView.target += 150;
  361.     } else if(-AlbumView.target/150 < AlbumView.max) {
  362.         AlbumView.target = AlbumView.target - 150;
  363.     }
  364.     AlbumView.glideTo(AlbumView.target,true);
  365.   },
  366.   /* JavaScript mouse wheel support */
  367.   wheel : function(event){
  368.     var delta = -event.detail/3;
  369.     AlbumView.handle(delta);
  370.     //event.preventDefault();
  371.   },
  372.   handleKeypress : function(event){
  373.     var KeyEvent = Ci.nsIDOMKeyEvent;
  374.     switch(event.keyCode){
  375.       case KeyEvent.DOM_VK_LEFT:
  376.         AlbumView.handle(1)
  377.         break;
  378.       case KeyEvent.DOM_VK_RIGHT:
  379.         AlbumView.handle(-1);
  380.         break;
  381.       //TODO: This won't work since it isn't focusable anymore
  382.       case KeyEvent.DOM_VK_RETURN:
  383.       case KeyEvent.DOM_VK_ENTER:
  384.         if (AlbumViewUtils && AlbumViewUtils.performAction){
  385.           var targetIndex = -AlbumView.target/150;
  386.           AlbumViewUtils.performAction(AlbumView.itemNodes[targetIndex]);
  387.         }
  388.     }
  389.   },
  390.   createImages : function(aImages){
  391.     var totalImages = aImages;
  392.     AlbumView.caption.value = "";
  393.     AlbumView.max = totalImages.length;
  394.     AlbumView.itemNodes = new Array(AlbumView.max);
  395.     AlbumView.itemImages = new Array(AlbumView.max);
  396.     AlbumView.itemProps = new Array(AlbumView.max);
  397.     /* remove any remaining children */
  398.     for (var i = AlbumView.max-1; i>=0; i--){
  399.       var src = totalImages[i];
  400.       AlbumView.lastOffsets[i]=i;
  401.       AlbumView.itemNodes[i]=src.node;
  402.       AlbumView.itemProps[i] = {caption : src.caption,
  403.                                 url : src.url};
  404.       AlbumView.itemImages[i]=new Image();
  405.       AlbumView.itemImages[i].setAttribute("onload",
  406.           "AlbumView.imageLoaded("+i+");");
  407.       AlbumView.itemImages[i].src = src.image;
  408.       if (AlbumView.itemImages[i].complete){
  409.         AlbumView.imageLoaded(i);
  410.       }
  411.     }
  412.     this.scrollbar.setAttribute("maxpos",AlbumView.max-1);
  413.   },
  414.   clearItems : function(){
  415.     this.max = 0;
  416.     this.itemNodes = [];
  417.     this.itemProps = [];
  418.     this.itemImages = [];
  419.     this.scrollbar.setAttribute("maxpos",0);
  420.   },
  421.   addItem : function(aItem){
  422.     var i = this.itemNodes.length;
  423.     this.scrollbar.setAttribute("maxpos",i);
  424.     this.max = i+1;
  425.     this.itemNodes.push(aItem.node);
  426.     this.itemProps.push({caption: aItem.caption,
  427.                           url: aItem.url});
  428.     if (i == 0){
  429.       this.caption.value = aItem.caption;
  430.     }
  431.     var img = new Image();
  432.     this.itemImages.push(img);
  433.     let j = i;
  434.     img.onload = function(){
  435.       AlbumView.imageLoaded(j);
  436.     }
  437.     img.src = aItem.image;
  438.     if (img.complete)
  439.       this.imageLoaded(i);
  440.   },
  441.   imageLoaded : function(idx){
  442.     if (!AlbumView.initiated)
  443.       return;
  444.     /*
  445.     Simply drawing the image once it has loaded won't work because then we could have
  446.     thumbnails on top of those closer to the center. We need to loop from the
  447.     last added thumbnail to center to avoid this problem.
  448.     If the image is out of view we don't need to draw anything else
  449.     */
  450.     var x = AlbumView.current + 150 * idx;
  451.     AlbumView.computeProperties(x,AlbumView.itemProps[idx]);
  452.     var targetIndex = -AlbumView.target / 150, canDraw = true;
  453.     if (idx>=targetIndex){
  454.       for (var i = idx; canDraw && i>=targetIndex; i--){
  455.         canDraw = AlbumView.drawImage(i, targetIndex);
  456.       }
  457.     }
  458.     else if (idx<targetIndex){
  459.       for (var i = idx; canDraw && i<=targetIndex; i++){
  460.         canDraw = AlbumView.drawImage(i, targetIndex);
  461.       }
  462.     }
  463.   },
  464.   setSize : function(ele,width,height){
  465.     ele.setAttribute("height",height);
  466.     ele.setAttribute("width",width);
  467.     ele.width=width;
  468.     ele.height=height;
  469.     ele.style.maxWidth = width;
  470.   }
  471. }
  472.